namespace IFFN {
    type p1<T> = T extends string ? string : never;
    type Z1 = p1<number>;

    //   ! 这两个代码不一致
    // 分布式条件类型
    type T1 = "x" | "y" extends "x" ? string : number; //返回number  已明确的类型会被当做一个整体去判断
    type T2<T> = T extends "x" | "y" ? T : never; //string | number   把T拆开然后去联合类型判断


    type T3 = T2<"x" | "y" | "c">;


    type p5<T> = [T] extends "x" | "y" ? T : never; //never   []括号包起来的是看做一个整体的

    type p9 = p5<"x">;


    // pick
    type p2<T, U> = T extends U ? T : unknown;

    type Z2 = p2<"a" | "b" | "c", "a" | "b">;

    //    //   这就是  exclude  工具类型的原理

    type p3<T, U> = T extends U ? never : T;
    type Z3 = p3<"a" | "b" | "c", "a" | "b">;


    // ^ 用途多结合泛型使用 列入函数的重载

    // *传统的实现
    interface nameLabel {
        name: string;
    }

    interface ageLabel {
        age: number;
    }

    // 利用条件
    function getLabel(name: string): nameLabel;
    function getLabel(id: string): ageLabel;
    function getLabel(nameorId: string | number): ageLabel | nameLabel;
    // 函数实现
    function getLabel(nameorId: string | number): ageLabel | nameLabel {
        if (typeof nameorId == "string") {
            return {name: "18"};
        } else {
            return {age: 18};
        }
    }

    //   使用条件类型判断
    type nameID<T extends string | number> = T extends string
        ? nameLabel
        : ageLabel;

    function getLabels<T extends string | number>(whichType: T): nameID<T> {
        if (typeof whichType === "string") {
            return {name: whichType} as nameID<T>;
        } else {
            return {age: whichType} as nameID<T>;
        }
    }

    let exE = getLabels("asd");
    let ex = getLabels(5);
    let exex = getLabels(Math.random() > 0.5 ? 5 : "asd")

    console.log(ex);

    // const exx = getLabels(52);

    type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;

    interface Email {
        message: string;
    }


    type EmailMessageContents = MessageOf<Email>;
    let emailS: EmailMessageContents = "aasdsa"


    type  Flattern<T> = T extends unknown[] ? T[number] : never
    type UseFla = Flattern<string[]>;


    /**
     在条件类型内进行推理       infer我的理解就是根据infer前面是否满足自动推断后面的
     */

    type  Flattern2<T> = T extends (infer U)[] ? U : never
    type UseFla2 = Flattern<string[]>;


    type GetReturnType<T> = T extends (...args: unknown[]) => infer R ? R : never;

    type num = GetReturnType<() => number>;

    type str = GetReturnType<(a: string, b: string, c: number) => string>;

    type neverr = GetReturnType<string>;


    type id = number[];
    type name = string[];

    type elementof<T> = T extends id ? number : T extends name ? string : never;
    type testof = elementof<string[]>;
    type testeof = elementof<number[]>;
    type testeeof = elementof<boolean>;


    // infer就是上面的语法糖
    // infer U表示U这个参数是 TypeScript 自己推断出来的，不用显式传入，
    // element<Type>则表示Type这个类型参数是外部传入的。T
    // T extends Array<infer U>则表示，如果参数Type是一个数组，
    // 那么就将该数组的成员类型推断为U，即U是从Type推断出来的。
    // 一旦使用Infer Item定义了Item，后面的代码就可以直接调用Item了。下面是上例的泛型Flatten<Type>的用法。
    // 意思就是 infer推断出T是否是数组如果是那么U则自动推断是数组的变量类型
    type element<T> = T extends (infer U)[] ? U : T;

    type test = element<id>;
    type teste = element<name>;
    type testee = element<boolean>;

    /**
     *^ 分布式条件类型  就是联合类型的官方语言  当使用联合类型会自动分布每一个类型是否符合

     */
    // any是除了never可以兼容

    type ToArray<Type> = Type extends any ? Type[] : never;

    type StrArrOrNumArr = ToArray<string | number>;  //数组

    // ! 两个不一样 第一个是 string[] | number[];  第二个是(string | number)[]
    type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
    // [Type] extends [any] 使用数组包装 Type，防止条件类型的分发行为。
    // 在 TypeScript 中，条件类型 T extends U ? X : Y 对于联合类型 T 会被分发，
    // 即如果 T 是 A | B，则条件类型会分别对 A 和 B 应用。
    // 通过将 Type 包装在数组中，[Type] extends [any]，可以避免这种分发行为。
    // 'ArrOfStrOrNum' is no longer a union.
    type ArrOfStrOrNum = ToArrayNonDist<string | number>;  //元组
}


